<template>
  <div class="voice-generation">
    <el-card class="main-card">
      <template #header>
        <div class="card-header">
          <span class="header-title">🎤 AI配音工具</span>
          <span class="header-subtitle">基于 CosyVoice 语音合成</span>
        </div>
      </template>

      <div class="generation-container">
        <!-- 左侧：参数设置 -->
        <div class="params-panel">
          <el-form :model="form" label-width="100px" label-position="top">
            <el-form-item label="模型选择" required>
              <el-select v-model="form.model" placeholder="请选择模型" style="width: 100%" @change="handleModelChange">
                <!-- <el-option label="cosyvoice-v3-plus（推荐，最佳效果）" value="cosyvoice-v3-plus" /> -->
                <!-- <el-option label="cosyvoice-v3（平衡质量与价格）" value="cosyvoice-v3" /> -->
                <el-option label="cosyvoice-v2（支持SSML）" value="cosyvoice-v2" />
                <!-- <el-option label="cosyvoice-v1" value="cosyvoice-v1" /> -->
              </el-select>
            </el-form-item>

            <div class="tip-text">
                <el-icon><InfoFilled /></el-icon>
                SSML仅支持cosyvoice-v2模型，可控制语速、语调、停顿等
              </div>
            <el-form-item label="SSML模式（可选）">
              <el-switch
                v-model="form.useSSML"
                active-text="启用SSML"
                :disabled="form.model !== 'cosyvoice-v2'"
                @change="handleSSMLChange"
              />

            </el-form-item>
            

            <el-form-item label="合成文本" required>
              <el-input
                v-model="form.text"
                type="textarea"
                :rows="form.useSSML ? 10 : 8"
                :placeholder="form.useSSML ? '请输入SSML文本，需包含在<speak></speak>标签内...' : '请输入要合成的文本，单次不超过2000字符（1个汉字=2字符，英文/数字/标点/空格=1字符）...'"
                maxlength="2000"
                show-word-limit
              />
              <div v-if="form.useSSML" class="ssml-toolbar">
                <el-button size="small" @click="insertSSMLTag('speak')">speak</el-button>
                <el-button size="small" @click="insertSSMLTag('break')">break</el-button>
                <el-button size="small" @click="insertSSMLTag('sub')">sub</el-button>
                <el-button size="small" @click="insertSSMLTag('phoneme')">phoneme</el-button>
                <el-button size="small" @click="insertSSMLTag('say-as')">say-as</el-button>
              </div>
              <div class="char-count">
                <span>字符数：{{ charCount }}</span>
                <span v-if="charCount > 2000" class="error-text">超出限制！</span>
              </div>
            </el-form-item>

            <el-form-item label="音色选择（可选）">
              <el-select
                v-model="form.voice"
                placeholder="选择音色（留空使用模型默认音色）"
                filterable
                clearable
                style="width: 100%"
              >
                <el-option-group
                  v-for="group in voiceOptions"
                  :key="group.category"
                  :label="group.category"
                >
                  <el-option
                    v-for="voice in group.voices"
                    :key="voice.value"
                    :label="`${voice.name}（${voice.trait}）`"
                    :value="voice.value"
                  >
                    <span style="float: left">{{ voice.name }}</span>
                    <span style="float: right; color: #8492a6; font-size: 13px">{{ voice.trait }}</span>
                  </el-option>
                </el-option-group>
              </el-select>
              <div class="tip-text">
                <el-icon><InfoFilled /></el-icon>
                不选择则使用模型默认音色
              </div>
            </el-form-item>

            <el-form-item label="音频格式">
              <el-radio-group v-model="form.format">
                <el-radio label="wav">WAV（无损）</el-radio>
                <el-radio label="mp3">MP3（压缩）</el-radio>
                <el-radio label="pcm">PCM（原始）</el-radio>
              </el-radio-group>
            </el-form-item>

            <el-form-item label="采样率">
              <el-radio-group v-model="form.sampleRate">
                <el-radio :label="16000">16kHz</el-radio>
                <el-radio :label="22050">22.05kHz</el-radio>
                <el-radio :label="24000">24kHz</el-radio>
                <el-radio :label="44100">44.1kHz</el-radio>
                <el-radio :label="48000">48kHz</el-radio>
              </el-radio-group>
            </el-form-item>

            <el-form-item>
              <el-button
                type="primary"
                size="large"
                :loading="generating"
                :disabled="!canGenerate"
                @click="handleGenerate"
                style="width: 100%"
              >
                <el-icon v-if="!generating"><Microphone /></el-icon>
                {{ generating ? '合成中...' : '开始合成' }}
              </el-button>
            </el-form-item>
          </el-form>
        </div>

        <!-- 右侧：结果展示 -->
        <div class="result-panel">
          <div v-if="!audioUrl && !generating" class="empty-state">
            <el-icon :size="80"><Headset /></el-icon>
            <p>合成的音频将在这里显示</p>
          </div>

          <div v-if="generating" class="generating-state">
            <el-progress :percentage="progress" :show-text="false" />
            <p>正在合成语音，请稍候...</p>
          </div>

          <div v-if="audioUrl" class="audio-result">
            <div class="audio-player">
              <audio :src="audioUrl" controls style="width: 100%"></audio>
            </div>
            <div class="audio-actions">
              <el-button
                type="primary"
                :icon="Download"
                @click="downloadAudio"
              >
                下载音频
              </el-button>
              <el-button
                type="success"
                :icon="CopyDocument"
                @click="copyAudioUrl"
              >
                复制链接
              </el-button>
            </div>
            <div v-if="audioInfo" class="audio-info">
              <p><strong>格式：</strong>{{ audioInfo.format }}</p>
              <p><strong>采样率：</strong>{{ audioInfo.sampleRate }}Hz</p>
              <p v-if="audioInfo.duration"><strong>时长：</strong>{{ audioInfo.duration }}秒</p>
            </div>
          </div>
        </div>
      </div>
    </el-card>
  </div>
</template>

<script setup>
import { ref, reactive, computed } from 'vue'
import { ElMessage } from 'element-plus'
import {
  Microphone,
  Download,
  CopyDocument,
  Headset,
  InfoFilled
} from '@element-plus/icons-vue'
import { voiceApi } from '@/services/voiceApi'

defineOptions({
  name: 'VoiceGeneration'
})

// 表单数据
const form = reactive({
  model: 'cosyvoice-v2',
  text: '',
  voice: '',
  format: 'mp3',
  sampleRate: 24000,
  useSSML: false
})

const generating = ref(false)
const progress = ref(0)
const audioUrl = ref('')
const audioInfo = ref(null)

// 音色选项数据（按适用场景分类）
const voiceOptions = ref([
  {
    category: '电话销售',
    voices: [
      { name: '龙应笑', trait: '清甜推销女', value: 'longyingxiao' }
    ]
  },
  {
    category: '短视频配音',
    voices: [
      { name: '龙机器', trait: '呆萌机器人', value: 'longjiqi' },
      { name: '龙猴哥', trait: '经典猴哥', value: 'longhouge' },
      { name: '龙机心', trait: '毒舌心机女', value: 'longjixin' },
      { name: '龙安粤', trait: '欢脱粤语男', value: 'longanyue' },
      { name: '龙港妹', trait: 'TVB港剧国语女', value: 'longgangmei' },
      { name: '龙陕哥', trait: '原味陕北男', value: 'longshange' },
      { name: '龙安敏', trait: '甜美闽南女', value: 'longanmin' },
      { name: '龙黛玉', trait: '娇率才女音', value: 'longdaiyu' },
      { name: '龙高僧', trait: '得道高僧音', value: 'longgaoseng' }
    ]
  },
  {
    category: '语音助手',
    voices: [
      { name: '龙安莉', trait: '利落从容女', value: 'longanli' },
      { name: '龙安朗', trait: '清爽利落男', value: 'longanlang' },
      { name: '龙安温', trait: '优雅知性女', value: 'longanwen' },
      { name: '龙安昀', trait: '居家暖男', value: 'longanyun' },
      { name: 'YUMI', trait: '正经青年女', value: 'longyumi_v2' },
      { name: '龙小淳', trait: '知性积极女', value: 'longxiaochun_v2' },
      { name: '龙小夏', trait: '沉稳权威女', value: 'longxiaoxia_v2' }
    ]
  },
  {
    category: '有声书',
    voices: [
      { name: '龙逸尘', trait: '洒脱活力男', value: 'longyichen' },
      { name: '龙婉君', trait: '细腻柔声女', value: 'longwanjun' },
      { name: '龙老伯', trait: '沧桑岁月爷', value: 'longlaobo' },
      { name: '龙老姨', trait: '烟火从容阿姨', value: 'longlaoyi' },
      { name: '龙白芷', trait: '睿气旁白女', value: 'longbaizhi' },
      { name: '龙三叔', trait: '沉稳质感男', value: 'longsanshu' },
      { name: '龙修', trait: '博才说书男', value: 'longxiu_v2' },
      { name: '龙妙', trait: '抑扬顿挫女', value: 'longmiao_v2' },
      { name: '龙悦', trait: '温暖磁性女', value: 'longyue_v2' },
      { name: '龙楠', trait: '睿智青年男', value: 'longnan_v2' },
      { name: '龙媛', trait: '温暖治愈女', value: 'longyuan_v2' }
    ]
  },
  {
    category: '社交陪伴',
    voices: [
      { name: '龙安亲', trait: '亲和活泼女', value: 'longanqin' },
      { name: '龙安雅', trait: '高雅气质女', value: 'longanya' },
      { name: '龙安朔', trait: '干净清爽男', value: 'longanshuo' },
      { name: '龙安灵', trait: '思维灵动女', value: 'longanling' },
      { name: '龙安智', trait: '睿智轻熟男', value: 'longanzhi' },
      { name: '龙安柔', trait: '温柔闺蜜女', value: 'longanrou' },
      { name: '龙嫱', trait: '浪漫风情女', value: 'longqiang_v2' },
      { name: '龙寒', trait: '温暖痴情男', value: 'longhan_v2' },
      { name: '龙星', trait: '温婉邻家女', value: 'longxing_v2' },
      { name: '龙华', trait: '元气甜美女', value: 'longhua_v2' },
      { name: '龙婉', trait: '积极知性女', value: 'longwan_v2' },
      { name: '龙橙', trait: '智慧青年男', value: 'longcheng_v2' },
      { name: '龙菲菲', trait: '甜美娇气女', value: 'longfeifei_v2' },
      { name: '龙小诚', trait: '磁性低音男', value: 'longxiaocheng_v2' },
      { name: '龙哲', trait: '呆板大暖男', value: 'longzhe_v2' },
      { name: '龙颜', trait: '温暖春风女', value: 'longyan_v2' },
      { name: '龙天', trait: '磁性理智男', value: 'longtian_v2' },
      { name: '龙泽', trait: '温暖元气男', value: 'longze_v2' },
      { name: '龙邵', trait: '积极向上男', value: 'longshao_v2' },
      { name: '龙浩', trait: '多情忧郁男', value: 'longhao_v2' },
      { name: '龙深', trait: '实力歌手男', value: 'kabuleshen_v2' }
    ]
  },
  {
    category: '童声（标杆音色）',
    voices: [
      { name: '龙呼呼', trait: '天真烂漫女童', value: 'longhuhu' }
    ]
  },
  {
    category: '消费电子-教育培训',
    voices: [
      { name: '龙安培', trait: '青少年教师女', value: 'longanpei' }
    ]
  },
  {
    category: '消费电子-儿童陪伴',
    voices: [
      { name: '龙汪汪', trait: '台湾少年音', value: 'longwangwang' },
      { name: '龙泡泡', trait: '飞天泡泡音', value: 'longpaopao' }
    ]
  },
  {
    category: '消费电子-儿童有声书',
    voices: [
      { name: '龙闪闪', trait: '戏剧化童声', value: 'longshanshan' },
      { name: '龙牛牛', trait: '阳光男童声', value: 'longniuniu' }
    ]
  },
  {
    category: '客服',
    voices: [
      { name: '龙应沐', trait: '优雅知性女', value: 'longyingmu' },
      { name: '龙应询', trait: '年轻青涩男', value: 'longyingxun' },
      { name: '龙应催', trait: '严肃催收男', value: 'longyingcui' },
      { name: '龙应答', trait: '开朗高音女', value: 'longyingda' },
      { name: '龙应静', trait: '低调冷静女', value: 'longyingjing' },
      { name: '龙应严', trait: '义正严辞女', value: 'longyingyan' },
      { name: '龙应甜', trait: '温柔甜美女', value: 'longyingtian' },
      { name: '龙应冰', trait: '尖锐强势女', value: 'longyingbing' },
      { name: '龙应桃', trait: '温柔淡定女', value: 'longyingtao' },
      { name: '龙应聆', trait: '温和共情女', value: 'longyingling' }
    ]
  },
  {
    category: '直播带货',
    voices: [
      { name: '龙安燃', trait: '活泼质感女', value: 'longanran' },
      { name: '龙安宣', trait: '经典直播女', value: 'longanxuan' },
      { name: '龙安冲', trait: '激情推销男', value: 'longanchong' },
      { name: '龙安萍', trait: '高亢直播女', value: 'longanping' }
    ]
  },
  {
    category: '童声',
    voices: [
      { name: '龙杰力豆', trait: '阳光顽皮男', value: 'longjielidou_v2' },
      { name: '龙铃', trait: '稚气呆板女', value: 'longling_v2' },
      { name: '龙可', trait: '懵懂乖乖女', value: 'longke_v2' },
      { name: '龙仙', trait: '豪放可爱女', value: 'longxian_v2' }
    ]
  },
  {
    category: '方言',
    voices: [
      { name: '龙老铁', trait: '东北直率男', value: 'longlaotie_v2' },
      { name: '龙嘉怡', trait: '知性粤语女', value: 'longjiayi_v2' },
      { name: '龙桃', trait: '积极粤语女', value: 'longtao_v2' }
    ]
  },
  {
    category: '诗词朗诵',
    voices: [
      { name: '龙飞', trait: '热血磁性男', value: 'longfei_v2' },
      { name: '李白', trait: '古代诗仙男', value: 'libai_v2' },
      { name: '龙津', trait: '优雅温润男', value: 'longjin_v2' }
    ]
  },
  {
    category: '新闻播报',
    voices: [
      { name: '龙书', trait: '沉稳青年男', value: 'longshu_v2' },
      { name: 'Bella2.0', trait: '精准干练女', value: 'loongbella_v2' },
      { name: '龙硕', trait: '博才干练男', value: 'longshuo_v2' },
      { name: '龙小白', trait: '沉稳播报女', value: 'longxiaobai_v2' },
      { name: '龙婧', trait: '典型播音女', value: 'longjing_v2' },
      { name: 'loongstella', trait: '飒爽利落女', value: 'loongstella_v2' }
    ]
  },
  {
    category: '出海营销-日语',
    voices: [
      { name: 'loongyuuna', trait: '元气霓虹女', value: 'loongyuuna_v2' },
      { name: 'loongyuuma', trait: '干练霓虹男', value: 'loongyuuma_v2' },
      { name: 'loongtomoka', trait: '日语女', value: 'loongtomoka_v2' },
      { name: 'loongtomoya', trait: '日语男', value: 'loongtomoya_v2' }
    ]
  },
  {
    category: '出海营销-韩语',
    voices: [
      { name: 'loongjihun', trait: '阳光韩国男', value: 'loongjihun_v2' },
      { name: 'loongkyong', trait: '韩语女', value: 'loongkyong_v2' }
    ]
  },
  {
    category: '出海营销-英式英文',
    voices: [
      { name: 'loongeva', trait: '知性英文女', value: 'loongeva_v2' },
      { name: 'loongbrian', trait: '沉稳英文男', value: 'loongbrian_v2' },
      { name: 'loongluna', trait: '英式英文女', value: 'loongluna_v2' },
      { name: 'loongluca', trait: '英式英文男', value: 'loongluca_v2' },
      { name: 'loongemily', trait: '英式英文女', value: 'loongemily_v2' },
      { name: 'loongeric', trait: '英式英文男', value: 'loongeric_v2' }
    ]
  },
  {
    category: '出海营销-美式英文',
    voices: [
      { name: 'loongabby', trait: '美式英文女', value: 'loongabby_v2' },
      { name: 'loongannie', trait: '美式英文女', value: 'loongannie_v2' },
      { name: 'loongandy', trait: '美式英文男', value: 'loongandy_v2' },
      { name: 'loongava', trait: '美式英文女', value: 'loongava_v2' },
      { name: 'loongbeth', trait: '美式英文女', value: 'loongbeth_v2' },
      { name: 'loongbetty', trait: '美式英文女', value: 'loongbetty_v2' },
      { name: 'loongcindy', trait: '美式英文女', value: 'loongcindy_v2' },
      { name: 'loongcally', trait: '美式英文女', value: 'loongcally_v2' },
      { name: 'loongdavid', trait: '美式英文男', value: 'loongdavid_v2' },
      { name: 'loongdonna', trait: '美式英文女', value: 'loongdonna_v2' }
    ]
  }
])

// 计算字符数（1个汉字=2字符，英文/数字/标点/空格=1字符）
const charCount = computed(() => {
  if (!form.text) return 0
  let count = 0
  for (let i = 0; i < form.text.length; i++) {
    const char = form.text[i]
    // 判断是否为汉字（Unicode范围：\u4e00-\u9fa5）
    if (/[\u4e00-\u9fa5]/.test(char)) {
      count += 2
    } else {
      count += 1
    }
  }
  return count
})

const canGenerate = computed(() => {
  return form.text.trim().length > 0 && form.model && charCount.value <= 2000
})

// 处理模型切换
const handleModelChange = (model) => {
  // 如果切换到非v2模型且SSML已启用，自动关闭SSML
  if (model !== 'cosyvoice-v2' && form.useSSML) {
    form.useSSML = false
    ElMessage.info('已自动关闭SSML模式（仅cosyvoice-v2支持）')
  }
}

// 处理SSML模式变化
const handleSSMLChange = (value) => {
  if (value && form.model !== 'cosyvoice-v2') {
    ElMessage.warning('SSML模式仅支持cosyvoice-v2模型，请先切换模型')
    form.useSSML = false
    return
  }
  if (value && !form.text.includes('<speak>')) {
    // 如果启用SSML但文本中没有speak标签，提示用户
    ElMessage.info('提示：使用SSML时，文本需包含在<speak></speak>标签内')
  }
}

// 插入SSML标签
const insertSSMLTag = (tagName) => {
  // 使用nextTick确保DOM已更新
  setTimeout(() => {
    const textarea = document.querySelector('.el-textarea__inner')
    if (!textarea) {
      ElMessage.warning('无法找到文本输入框')
      return
    }
    
    const start = textarea.selectionStart
    const end = textarea.selectionEnd
    const selectedText = form.text.substring(start, end)
  
  let insertText = ''
  switch (tagName) {
    case 'speak':
      insertText = `<speak>${selectedText || '文本内容'}</speak>`
      break
    case 'break':
      insertText = `<break time="500ms"/>`
      break
    case 'sub':
      insertText = `<sub alias="替换文本">${selectedText || '原始文本'}</sub>`
      break
    case 'phoneme':
      insertText = `<phoneme alphabet="py" ph="pin1 yin1">${selectedText || '文本'}</phoneme>`
      break
    case 'say-as':
      insertText = `<say-as interpret-as="cardinal">${selectedText || '123'}</say-as>`
      break
  }
  
    const newText = form.text.substring(0, start) + insertText + form.text.substring(end)
    form.text = newText
    
    // 设置光标位置
    setTimeout(() => {
      textarea.focus()
      const newPos = start + insertText.length
      textarea.setSelectionRange(newPos, newPos)
    }, 0)
  }, 0)
}

// 生成语音
const handleGenerate = async () => {
  if (!canGenerate.value) {
    ElMessage.warning('请填写合成文本，且字符数不超过2000')
    return
  }

  if (charCount.value > 2000) {
    ElMessage.error('文本字符数超过2000，请缩短文本')
    return
  }

  generating.value = true
  progress.value = 0
  audioUrl.value = ''
  audioInfo.value = null

  // 模拟进度
  const progressInterval = setInterval(() => {
    if (progress.value < 90) {
      progress.value += Math.random() * 15
    }
  }, 300)

  try {
    const params = {
      model: form.model,
      text: form.text,
      format: form.format,
      sampleRate: form.sampleRate,
      useSSML: form.useSSML
    }

    if (form.voice && form.voice.trim()) {
      params.voice = form.voice.trim()
    }
    
    // 如果使用SSML，验证模型
    if (form.useSSML && form.model !== 'cosyvoice-v2') {
      ElMessage.error('SSML模式仅支持cosyvoice-v2模型')
      generating.value = false
      return
    }

    const response = await voiceApi.generateVoice(params)

    clearInterval(progressInterval)
    progress.value = 100

    if (response && response.data) {
      // 处理返回的音频数据
      if (response.data.url) {
        audioUrl.value = response.data.url
      } else if (response.data.b64Json) {
        // Base64格式，转换为blob URL
        const audioData = response.data.b64Json
        const mimeType = getMimeType(form.format)
        const base64Data = audioData.startsWith('data:') 
          ? audioData.split(',')[1] 
          : audioData
        const binaryString = atob(base64Data)
        const bytes = new Uint8Array(binaryString.length)
        for (let i = 0; i < binaryString.length; i++) {
          bytes[i] = binaryString.charCodeAt(i)
        }
        const blob = new Blob([bytes], { type: mimeType })
        audioUrl.value = URL.createObjectURL(blob)
      }

      audioInfo.value = {
        format: form.format,
        sampleRate: form.sampleRate,
        duration: response.data.duration || null
      }

      ElMessage.success('语音合成成功！')
    } else {
      throw new Error('未返回音频数据')
    }
  } catch (error) {
    clearInterval(progressInterval)
    progress.value = 0
    console.error('生成语音失败:', error)
    
    // 处理超时错误
    if (error.code === 'ECONNABORTED' || error.message?.includes('timeout')) {
      ElMessage.error('请求超时，语音合成可能需要更长时间，请稍后重试或检查网络连接')
    } else {
      ElMessage.error('合成失败：' + (error.message || '未知错误'))
    }
  } finally {
    generating.value = false
    setTimeout(() => {
      progress.value = 0
    }, 1000)
  }
}

// 获取MIME类型
const getMimeType = (format) => {
  const mimeMap = {
    'wav': 'audio/wav',
    'mp3': 'audio/mpeg',
    'pcm': 'audio/pcm'
  }
  return mimeMap[format] || 'audio/mpeg'
}

// 下载音频
const downloadAudio = async () => {
  try {
    if (!audioUrl.value) {
      ElMessage.warning('没有可下载的音频')
      return
    }

    const response = await fetch(audioUrl.value)
    const blob = await response.blob()
    const url = window.URL.createObjectURL(blob)
    const link = document.createElement('a')
    link.href = url
    link.download = `voice-${Date.now()}.${form.format}`
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
    window.URL.revokeObjectURL(url)

    ElMessage.success('音频下载成功')
  } catch (error) {
    console.error('下载音频失败:', error)
    ElMessage.error('下载失败')
  }
}

// 复制音频链接
const copyAudioUrl = async () => {
  try {
    if (!audioUrl.value) {
      ElMessage.warning('没有可复制的链接')
      return
    }
    await navigator.clipboard.writeText(audioUrl.value)
    ElMessage.success('链接已复制到剪贴板')
  } catch (error) {
    console.error('复制失败:', error)
    ElMessage.error('复制失败')
  }
}
</script>

<style scoped>
.voice-generation {
  padding: 20px;
  max-width: 1400px;
  margin: 0 auto;
}

.main-card {
  min-height: 600px;
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.header-title {
  font-size: 20px;
  font-weight: bold;
  color: #2c3e50;
}

.header-subtitle {
  font-size: 14px;
  color: #909399;
}

.generation-container {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 24px;
  margin-top: 20px;
}

.params-panel {
  padding-right: 20px;
  border-right: 1px solid #e4e7ed;
}

.result-panel {
  min-height: 500px;
}

.empty-state,
.generating-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100%;
  color: #909399;
}

.empty-state p,
.generating-state p {
  margin-top: 16px;
  font-size: 14px;
}

.generating-state {
  padding: 40px;
}

.generating-state .el-progress {
  width: 300px;
  margin-bottom: 16px;
}

.audio-result {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.audio-player {
  width: 100%;
  padding: 20px;
  background: #f5f7fa;
  border-radius: 8px;
}

.audio-actions {
  display: flex;
  gap: 12px;
  justify-content: center;
}

.audio-info {
  padding: 16px;
  background: #f5f7fa;
  border-radius: 8px;
  font-size: 14px;
}

.audio-info p {
  margin: 8px 0;
  color: #606266;
}

.char-count {
  margin-top: 8px;
  font-size: 12px;
  color: #909399;
}

.error-text {
  color: #f56c6c;
  margin-left: 8px;
}

.tip-text {
  margin-top: 8px;
  font-size: 12px;
  color: #909399;
  display: flex;
  align-items: center;
  gap: 4px;
}

.ssml-toolbar {
  margin-top: 8px;
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

@media (max-width: 1024px) {
  .generation-container {
    grid-template-columns: 1fr;
  }

  .params-panel {
    padding-right: 0;
    border-right: none;
    border-bottom: 1px solid #e4e7ed;
    padding-bottom: 24px;
    margin-bottom: 24px;
  }
}
</style>

